--TODO: address counter- INTERFAZ DE CONTROL PARA UART/ROTADOR. 

library ieee;
use ieee.std_logic_1164.all;

entity ascii_parser is
	port(
		clk,reset : in std_logic;
		ascii: in std_logic_vector(7 downto 0);
		rx_done_tick: in std_logic; -- enable
--		ascii_parser_tick: out std_logic;autocomplete
		is_digit, is_blank, is_esc, is_minus: out std_logic
		);
end ascii_parser;

architecture arch of ascii_parser is
	signal prev_blank, current_blank: std_logic;
	signal aux_is_digit, is_dot, is_minus_aux : std_logic;
--	signal ascii_parser_tick_delay: std_logic; -- Genero un delay en el tick para evitar carreras.

	FUNCTION bool2stdlogic(B1:boolean) return std_logic is
	begin
		if B1 then
			return '1';
		else
			return '0';
		end if;
	end bool2stdlogic;
begin
	-- Sin mucha magia, los numeros punto fijo que se ingresan tienen que ocupar toda la grilla. El punto se ignora.
	-- Cuidado que los controles son asincrónicos.

	is_dot <=  bool2stdlogic(ascii = "00101110");--0x2E  ascii del punto 
   	aux_is_digit <=  bool2stdlogic(ascii(7 downto 4) = "0011") and not (ascii(3) and ( ascii(2) or ascii(1) ));
	is_digit <= aux_is_digit;
	current_blank <= not aux_is_digit and not is_dot; -- si no es punto o numero es blanco.
	is_esc <= bool2stdlogic(ascii = X"1B");  --27 El caracter <ESC> es <EOF> y blanco.
	is_minus_aux <= bool2stdlogic(ascii = "00101101");--0x2D
	is_minus <= is_minus_aux;
	is_blank <= current_blank and not prev_blank;  -- evitar doble blancos

R2D2:	process(clk , reset)
		begin
		if reset = '1' then
	  		prev_blank <= '1'; --arranca en 1 pa' no comerte blancos al principio
		elsif clk = '1' and clk'event then
			if rx_done_tick = '1' then
				if ( is_dot OR is_minus_aux ) = '0' then
					prev_blank <= current_blank;
				end if;
			end if;
--			ascii_parser_tick<=ascii_parser_tick_delay;		
--			ascii_parser_tick_delay<=rx_done_tick;
		end if;
	end process;
end arch;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity bcd2binV2 is
	generic(
		W: integer:=37 --numero de bits necesarios 0.3779969228
	);
	port(
		clk, reset : in std_logic;
		bcd_in: in std_logic_vector(3 downto 0); --BCD desempaquetado.
		dout: out std_logic_vector(W-1 downto 0);
		new_output_flag: out std_logic;
		sign: out std_logic; --Signo menos, Si aparece un menos (en cualquier lugar), se levanta.
		is_digit, is_blank, is_minus, enable : in std_logic
	);
end bcd2binV2;


architecture arch of bcd2binV2 is
--	type state_type is (idle, start, data, stop);
	signal buf_reg, buf_prev: unsigned(W-1 downto 0);
	signal buf_minus: std_logic;
begin
R1:	process(clk , reset)
	begin
		if reset='1' then
			dout <= (others=>'0');
			buf_prev <= (others=>'0');
			buf_minus <= '0';
			new_output_flag <= '0';
--????		aux_blank <= '0';
		elsif clk = '1' and clk'event then 
			new_output_flag <= '0';
			if enable='1' then	
				if is_digit='1' then
					buf_prev <= buf_reg;	--Se latchea 2 veces
					sign <= buf_minus;
					dout <= std_logic_vector(buf_reg);		--Para mejorar la velocidad
				elsif is_blank='1' then
					buf_prev <= (others =>'0'); --blank no borra la salida.
					new_output_flag <= '1';
					buf_minus <= '0';
				elsif is_minus='1' then
					buf_minus <= '1';
					sign <= '1';
				end if;
			end if;
		end if;
	end process;

buf_reg <= (buf_prev sll 3) + (buf_prev sll 1) + unsigned(bcd_in);


end arch;

------------------------------------------------
------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity memoryLoader is
	generic(
		W: integer:=37; --numero de bits por coordenada. 
		WORDS: integer:=3; --numero de WORDS por coordenada.
		DBUS: integer:=16 --bus de datos de la memoria.
	);
	port(
		clk, reset : in std_logic;
		crash_flag : out std_logic;
--Desde Serie
		enable : in std_logic; -- El enable se dispara con un is_blank.
		din: in std_logic_vector(W-1 downto 0);
		sign_in: in std_logic;
--A memoria
		mem_out: out std_logic;
		ready: in std_logic;
		dout: out std_logic_vector(DBUS-1 downto 0)
	);
end memoryLoader;

architecture arch of memoryLoader is

--Nota: Asumo que escribir una coordenada tarda menos que recibir 8 bits por puerto serie para no latchear la entrada.
	type state_type is (stateA, stateB, stateC, crash);
	signal state_reg: state_type;
	signal mem: std_logic;
	signal sign: std_logic; --Hack para extensión de signo.
	signal state_reg_alias: integer; --DEBUG

	FUNCTION crashUpdate(state_reg:state_type) return std_logic is
	begin
		if state_reg = crash then
			return '1';
		else
			return '0';
		end if;
	end crashUpdate;
begin

--GENERALIZACION... SI ES 1 SOLO WORD, PONGO UN CABLE.
GA: 	if WORDS < 2 generate
	begin
		mem_out<=enable;
		dout<=din;
		crash_flag<='0';

	end generate;
--TODO:Esta desenrolloado.. Arreglar y generalizar.
GB:	if WORDS > 1 generate
	begin

DEBUG:		process(state_reg)
			begin
			case state_reg is
				when stateC => state_reg_alias <= 0; --2 CLK'S
				when stateA => state_reg_alias <= 1; --1 CLK
				when stateB => state_reg_alias <= 2; --1 CLK
				when crash =>  state_reg_alias <= 3; -- 8 acostado :p
			end case;
		end process;
		
ZERO_CHECK:
		process(sign_in,din)
		begin
		if din = std_logic_vector( to_unsigned(0, din'length) ) then
			sign<='0';
		else
			sign<=sign_in;
		end if;
		end process;

S1:		process(clk , reset)
		begin
	--Nota: 4 clocks por WORD (12 por coordenada).
			if reset='1' then
				mem <= '0';
				state_reg <=stateC; --estadoC + ready=1 es iddle;
				dout<=din(15 downto 0);
			elsif clk = '1' and clk'event then
				case state_reg is
					when stateC =>
						if enable='1' then --Comienza a grabar!
							if ready = '1' and mem = '0' then --Si estaba en Iddle
								state_reg <= stateA;
								mem<='1';
							else --Si no esaba en iddle Explota.
								mem<='0';
								state_reg <=crash;
							end if;
						else --veamos que pasa
							mem<='0';
							dout<=din(DBUS-1 downto 0);
						end if;

					when stateA=>
						if enable='1' then
							mem<='0';
							state_reg <=crash;
						else
							if mem='1' then --Entra desde stateB, calcula stateA.
								mem<='0';
								dout<=din(DBUS*2-1 downto DBUS);
							else 
								if ready='1' then
									mem<='1';
									state_reg <= stateB;
								end if;
							end if;					
						end if;	

					when stateB=>
						if enable='1' then
							mem<='0';
							state_reg <=crash;
						else
							if mem='1' then --Entra desde stateB, calcula stateA.
								mem<='0';
								dout(15 downto W-DBUS*2)<=(others => sign); -- Completa con el signo;
								dout(W-DBUS*2-1 downto 0)<= din(W-1  downto DBUS*2);
							else
								if ready='1' then
									mem<='1';
									state_reg <= stateC;
								end if;
							end if;					
						end if;
					when others => -- no hace na'
				end case;
			end if;
		end process;

		mem_out <= mem;
		
		crash_flag<=crashUpdate(state_reg);
		
	end generate;

end arch;


--------------------------------------
--------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity addressCounter is
	generic(
		ABUS: integer:=18 --bus de dirección de l memoria.
	);
		
	port(
		clk, reset, enable: in std_logic; -- El enable se dispara con mem.
--		load: in std_logic; --Utilizados en posible carga de dirección
--		address_input: out std_logic_vector(ABUS-1 downto 0);
		address_out: out std_logic_vector(ABUS-1 downto 0)
	);
end addressCounter;

architecture arch of addressCounter is
	signal address: unsigned(ABUS-1 downto 0);
begin
K2:	process(clk , reset)
	begin
		if reset='1' then
			address <= (others=>'0');
		elsif clk = '1' and clk'event and enable = '1' then
--Descomentar para habilitar carga de dirección.
--			if load='1' then
--				address <= unsigned(address_input); -- direcciona de a Word!
--			else
				address <= address+1; -- direcciona de a Word!
--			end if;
		end if;
	end process;
	address_out <= std_logic_vector(address);
end arch;

--------------------------------------
--------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity twosComplement is 	
	generic(
		W: integer:=37 --numero de bits necesarios 0.3779969228
	);
	port(
		din: in std_logic_vector(W-1 downto 0);
		dout: out std_logic_vector(W-1 downto 0);
		sign: in std_logic
	);
end twosComplement;

architecture arch of twosComplement is
begin
SG:	process(sign,din)
	begin
	if sign= '1' then 
		dout<= std_logic_vector(unsigned( not din )+1);
	else
		dout <= din;
	end if;
	end process;
end arch;

--------------------------------------
--PARA MATIAS
--------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity memoryReader is
	generic(
		DBUS: integer:=16; --bus de datos de la memoria.
		WORDS: integer:=3; --palabras que ocupa una coordenada.
		BITS: integer:=4 --bits para representar los estados = ceil(log2(WORDS*3))
	);
	port(
		clk, reset : in std_logic;
--Al Control de address
		addTrig: out std_logic; --Enable para que aumente la dirección.

--Al Rotador
		read : in std_logic; 
		outX,outY,outZ: out std_logic_vector(DBUS*WORDS-1 downto 0);
		busy_out : out std_logic; --busy e' ocupado.
		vector_tick : out std_logic;
--A memoria
		mem_out: out std_logic;
		ready: in std_logic;
		din: in std_logic_vector(DBUS-1 downto 0)
	);
end memoryReader;


--Para no hacerlo desenrrollado me quedaron todas las señales separadas.
--Es muy probable que algo malga sal.

architecture arch of memoryReader is

type memBlock is array (integer range <>) of std_logic_vector(DBUS-1 downto 0);
signal auxBlock:  memBlock(WORDS*3-1 downto 0); --array de palabras dode demultiplexa la salida.
signal index, next_index: unsigned(BITS-1 downto 0);
signal mem, busy,aux_reset: std_logic;

begin



S2:	process(clk , reset, index)
	begin			
		if reset='1'  then --Valores para estado idle.
			busy <= '0';
			mem <= '0'; --Arranca el ultimo estado como viniendo de 8;
			index<=to_unsigned(WORDS*3-1,BITS); --CONTADOR RESETEA EN EL ULTIMO ESTADO
		elsif (index > WORDS*3 - 1) then --CONTADOR MODULO WORDS*3
			index<=(others => '0');
			vector_tick<='1';
		elsif clk = '1' and clk'event then			
			addTrig<='0';
			vector_tick<='0';
			if read='1' then
				busy <= '1';
			elsif index=to_unsigned(0,BITS) and ready='1' then
				busy <= '0';
			end if;

			if mem = '1' then -- aumento la direccion antes para no tener carreras.
				mem <='0';
				addTrig<='1'; --El módulo de control de memoria latchea la address
				--Si estoy en '0' es porque '8' ya pidió el valor para '0'.
				-- Entra salvo tras la transición index 8->0	
			elsif (read = '1' OR busy='1') and ready='1' then
				mem<='1';					
				index<=index+1;	
				auxBlock(to_integer(index))<=din;
			end if;
		end if;
	end process;
	
	mem_out <= mem;
	busy_out <= busy;

--CONCATENO LOS WORDS DE SALIDA
G1:	for N in WORDS downto 1 generate
		outX(N*DBUS-1 downto (N-1)*DBUS) <= auxBlock(N-1);
		outY(N*DBUS-1 downto (N-1)*DBUS) <= auxBlock(WORDS+N-1);
		outZ(N*DBUS-1 downto (N-1)*DBUS) <= auxBlock(2*WORDS+N-1);
	end generate;
	
end arch;



----------------------------------------------------------------
----------------------------------------------------------------
--DELAY, USADO PARA CONTROLAR EL MODO: UART/ROTADOR
library ieee;
use ieee.std_logic_1164.all;

entity FFD is
	generic(W:integer :=1);
	port( 
		clk, reset, set: in std_logic;
		prevQ: in std_logic_vector(W-1 downto 0);
		Q: out std_logic_vector(W-1 downto 0)
	    );
end FFD;

architecture arch of FFD is
	signal Qaux: std_logic_vector(W-1 downto 0);
begin
FFD0: process(clk,reset)
	begin
		Qaux<=Qaux;
		if reset = '1' then
			Qaux <=(others => '0');
		elsif clk='1' and clk'event and set='1' then
			Qaux<=prevQ;
		end if;
	end process;
	Q<=Qaux;
end arch;

--------------------------------------------------------------------
--------------------------------------------------------------------
--LATCH, Usado para controlar el MODO : UART/ROTADOR
library ieee;
use ieee.std_logic_1164.all;

entity LATCH is
	generic(W:integer :=1);
	port( 
		reset, set: in std_logic;
		prevQ: in std_logic_vector(W-1 downto 0);
		Q: out std_logic_vector(W-1 downto 0)
	    );
end LATCH;
architecture arch of LATCH is
	signal Qaux: std_logic_vector(W-1 downto 0);
begin
LATCH0: process(prevQ,set,reset)
	  begin
		Qaux<=Qaux;
		if reset = '1' then
			Qaux <=(others => '0');
		elsif set='1' then
			Qaux<=prevQ;
		end if;
	end process;
	Q<=Qaux;
end arch;

--------------------------------------------------------------------------
--------------------------------------------------------------------------
